package com.example.demo.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.example.demo.dto.TeacherDto;
import com.example.demo.dto.UserDto;
import com.example.demo.entity.UserEntity;
import com.example.demo.excel.CacheKey;
import com.example.demo.excel.ImportExcelDataListener;
import com.example.demo.exception.BusinessException;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import com.example.demo.util.BaseConstants;
import com.example.demo.vo.ExcelErrorVo;
import com.example.demo.vo.ExcelImportResultVo;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.math3.stat.inference.OneWayAnova;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * ServiceImpl实现了IService，提供了IService中基础功能的实现
 * 若ServiceImpl无法满足业务需求，则可以使用自定的UserService定义方法，并在实现类中实现
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements UserService {

    @Autowired
    UserMapper userMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public long count() {
        return 10;
    }

    @Override
    public String hello() {
        return "hello";
    }

    @Override
    public UserEntity getUserByid(int id) {
        return userMapper.selectById(id);
    }

    @Override
    public List<UserEntity> getAllUser() {
        return userMapper.selectList(null);
    }

    @Override
    public List<UserDto> getAllUsers() {
        return null;
    }

    @Override
    public ExcelImportResultVo importExcel(MultipartFile file, boolean f) {
        try {
            ImportExcelDataListener<UserDto> userExcelImportService = new ImportExcelDataListener<>("UserExcelImportService", 2000);
            EasyExcel.read(file.getInputStream(), UserDto.class, userExcelImportService).sheet(0).doRead();
            BoundHashOperations<String, Object, Object> myImportOps = getMyImportOps(userExcelImportService.getVersion());
            Map<Object, Object> entries = myImportOps.entries();
            redisTemplate.delete(myImportKey(userExcelImportService.getVersion()));
            ExcelImportResultVo resultVo = mapToExcelVo(entries);
            return resultVo;
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw (BusinessException) e;
            }
            e.printStackTrace();
            log.error("导入异常{}", e);
            throw new BusinessException("导入异常:" + e.getMessage());
        }
    }

    @Override
    public String importExcel(MultipartFile file) {
        try {
            ImportExcelDataListener<UserDto> userExcelImportService = new ImportExcelDataListener<>("UserExcelImportService", 2000);
            EasyExcel.read(file.getInputStream(), UserDto.class, userExcelImportService).sheet(0).doRead();
            BoundHashOperations<String, Object, Object> myImportOps = getMyImportOps(userExcelImportService.getVersion());
            Map<Object, Object> entries = myImportOps.entries();
            redisTemplate.delete(myImportKey(userExcelImportService.getVersion()));
            ExcelImportResultVo resultVo = mapToExcelVo(entries);
            if (resultVo != null) {
                return resultVo.toString();
            } else {
                return "";
            }

        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw (BusinessException) e;
            }
            e.printStackTrace();
            log.error("导入异常{}", e);
            throw new BusinessException("导入异常:" + e.getMessage());
        }
    }


    @Override
    public void exportExcels(List<UserDto> userDtoList, String fileName) throws IOException {
        EasyExcel.write(fileName, UserDto.class).sheet("用户信息").doWrite(() -> {
            // 分页查询数据
            return userDtoList;
        });
    }

    /**
     * 自定义导出
     *
     * @param userDtoList
     * @param fileName
     * @throws IOException
     */
    @Override
    public void customExport(List<UserDto> userDtoList, String fileName) throws IOException {
        InputStream template = getTemplateInputStream();
        ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(template).excelType(ExcelTypeEnum.XLSX).build();
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        TeacherDto teacherDto = new TeacherDto();
        teacherDto.setClasses("二班");
        teacherDto.setGrade("四年级");
        teacherDto.setSubject("语文");
        teacherDto.setTeacherName("马");
        excelWriter.fill(teacherDto, writeSheet);
        if (CollectionUtils.isNotEmpty(userDtoList)) {
            excelWriter.fill(userDtoList, writeSheet);
        }
        excelWriter.finish();
    }

    @Override
    public void sayHello(String name) {
        if (name == null || name.trim() == "") {
            throw new RuntimeException ("parameter is null!!");
        }
        System.out.println("hello " + name);
    }

    /**
     * 模板需要提前分配好合并行
     *
     * @return
     * @throws IOException
     */
    private InputStream getTemplateInputStream() throws IOException {
        ClassPathResource classPathResource = new ClassPathResource("templates/user_excel.xlsx");
        return classPathResource.getInputStream();
    }


    private ExcelImportResultVo mapToExcelVo(Map<Object, Object> entries) {
        if (org.apache.commons.lang3.ObjectUtils.isEmpty(entries)) {
            return null;
        }
        ExcelImportResultVo excelImportResultVo = new ExcelImportResultVo();
        List<ExcelErrorVo> list = new ArrayList<>();
        for (Map.Entry<Object, Object> entry : entries.entrySet()) {
            int rowIndex = Integer.parseInt(entry.getKey().toString());
            // 此行数为执行报错
            if (rowIndex == BaseConstants.IMPORT_FAIL) {
                throw new BusinessException(entry.getValue().toString());
            }

            if (rowIndex == BaseConstants.IMPORT_SUCCESS) {
                excelImportResultVo.setSuccessCount(Integer.parseInt(entry.getValue().toString()));
                continue;
            }
            ExcelErrorVo excelErrorVo = new ExcelErrorVo();
            excelErrorVo.setRowIndex(rowIndex);
            excelErrorVo.setErrorMsg(entry.getValue().toString());
            list.add(excelErrorVo);

        }
        list.sort(Comparator.comparing(ExcelErrorVo::getRowIndex));
        excelImportResultVo.setFailCount(list.size());
        excelImportResultVo.setFailData(list);
        return excelImportResultVo;
    }

    private BoundHashOperations<String, Object, Object> getMyImportOps(String version) {
        return redisTemplate.boundHashOps(myImportKey(version));
    }

    private String myImportKey(String version) {
        return String.format(CacheKey.IMPORT_EXCEL_SUPPLIER_KEY, version);
    }
}